package com.css.util;


import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 公用UTILS
 */
@Slf4j
public class GyUtils {
	public static final String smrzKey = ":certify_id:";
    private static final String[] dateFormatinfo = new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy年MM月dd日HH时mm分ss秒", "yyyy-MM-dd", "yyyy/MM/dd", "yy-MM-dd", "yy/MM/dd", "yyyy年MM月dd日", "HH:mm:ss", "yyyyMMddHHmmss", "yyyyMMdd", "yyyy.MM.dd", "yy.MM.dd", "yyyyMMddHHmmssSSS", "yyyy-MM-dd HH:mm:ss:SSS", "yyyy-MM-dd HH:mm:ss.SSS", "yyyy", "yyyyMM", "yyyyMMdd HH", "yyyyMMdd HH:mm", "yyyyMMdd HH:mm:ss"};

    /**
     * 判断对象是否为空
     *
     * @param obj Object
     * @return true/false
     */
    @SuppressWarnings("rawtypes")
    public static boolean isNull(Object obj) {
        boolean isNullFlag = true;
        if (obj != null) {
            if (obj instanceof List<?>) {
                isNullFlag = isNull((List<?>) obj);
            } else if (obj instanceof Set<?>) {
                isNullFlag = isNull((Set<?>) obj);
            } else if (obj instanceof Object[]) {
                isNullFlag = isNull((Object[]) obj);
            } else if (obj instanceof Map) {
                isNullFlag = isNull((Map) obj);
            } else if (obj instanceof String) {
                isNullFlag = isNull((String) obj);
            } else {
                isNullFlag = false;
            }
        }
        return isNullFlag;
    }

    /**
     * 是否是空
     *
     * @param list List类型
     * @return 是否是空
     */
    private static boolean isNull(List<?> list) {
        return list == null || list.size() == 0;
    }

    /**
     * 是否是空
     *
     * @param set Set类型
     * @return 是否是空
     */
    private static boolean isNull(Set<?> set) {
        return set == null || set.size() == 0;
    }

    /**
     * 是否是空
     *
     * @param objects Object数组
     * @return 是否是空
     */
    private static boolean isNull(Object[] objects) {
        return objects == null || objects.length == 0;
    }

    /**
     * 是否是空
     *
     * @param map Map类型
     * @return 是否是空
     */
    private static boolean isNull(Map<?, ?> map) {
        return map == null || map.isEmpty();
    }

    /**
     * 是否是空
     *
     * @param str String类型
     * @return 是否是空
     */
    private static boolean isNull(String str) {
        return str == null || "".equals(str.trim()) || "null".equalsIgnoreCase(str.trim());
    }

    /**
     * 是否非空
     *
     * @param obj obj
     * @return 是否是空
     */
    public static boolean isNotNull(Object obj) {
        return !isNull(obj);
    }

    /**
     * 判断2个字符串是否相等
     *
     * @param str1 输入参数1
     * @param str2 输入参数2
     * @return 比较结果
     */
    public static Boolean isEquals(String str1, String str2) {
        boolean flag;
        if (isNull(str1)) {
            flag = isNull(str2);
        } else {
            if (!isNull(str2)) {
                flag = str1.trim().equals(str2.trim());
            } else {
                flag = false;
            }
        }
        return flag;
    }


    /**
     * 字符串转驼峰格式
     *
     * @param str 字符串
     * @return 字符串
     */
    public static String conversStrToVoStyle(String str) {
        String tmp = str.toLowerCase();
        int ind = tmp.indexOf("_");
        while (ind >= 0) {
            tmp = tmp.substring(0, ind) + tmp.substring(ind + 1, ind + 2).toUpperCase() + tmp.substring(ind + 2);
            ind = tmp.indexOf("_");
        }
        return tmp;
    }

    /**
     * 获取数组长度
     *
     * @param list 列表
     * @return int 数值
     */
    public static int length(Collection<?> list) {
        return list == null ? 0 : list.size();
    }

    /**
     * 获取数组长度
     *
     * @param list 列表
     * @return int 数值
     */
    public static int length(List<?> list) {
        return list == null ? 0 : list.size();
    }

    /**
     * 获取数组长度
     *
     * @param objs object对象
     * @return int 数值
     */
    public static int length(Object[] objs) {
        return objs == null ? 0 : objs.length;
    }

    /**
     * 获取Map的长度
     *
     * @param map 集合
     * @return int 数值
     */
    @SuppressWarnings({"rawtypes"})
    public static int length(Map map) {
        return map == null ? 0 : map.size();
    }

    /**
     * 获取字符串长度
     *
     * @param str 字符串
     * @return int 数值
     */
    public static int length(String str) {
        return str == null ? 0 : str.length();
    }

    /**
     * 根据Key获取PO（MAP）中的属性值
     *
     * @param list list
     * @param key  key
     * @return value
     */
    public static Set<String> getValueByKey(Collection<?> list, String key) {
        final Set<String> valueSet = new HashSet<>();
        if (isNotNull(list)) {
            for (Object item : list) {
                final String value = getValueByKey(item, key);
                if (isNotNull(item)) {
                    valueSet.add(value);
                }
            }
        }
        return valueSet;
    }

    public static <T, R> Set<R> getValueByKey(Collection<T> list, Function<T, R> key) {
        final Set<R> valueSet = new HashSet<>();
        if (isNotNull(list)) {
            for (T item : list) {
                final R value = key.apply(item);
                if (isNotNull(item)) {
                    valueSet.add(value);
                }
            }
        }
        return valueSet;
    }

    /**
     * 根据Key获取PO（MAP）中的属性值
     *
     * @param vo  vo
     * @param key key
     * @return value
     */
    public static String getValueByKey(Object vo, String key) {
        // final Object keyValueObj = ExpressionUtils.getValue(vo, key);
        final String keyValue;

        if (vo instanceof Map<?, ?>) {
            final Object keyValueObj = ((Map<?, ?>) vo).get(key);
            keyValue = getStringValue(keyValueObj);
        } else {
            final String methodName = "get" +
                    key.substring(0, 1).toUpperCase() +
                    key.substring(1);
            try {
                final Method m = vo.getClass().getMethod(methodName);
                final Object keyValueObj = m.invoke(vo);
                keyValue = getStringValue(keyValueObj);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                //捕获反射异常，抛出框架异常
                final String className = vo.getClass().getName();
                final Map<String, Object> errMap = new HashMap<>();
                errMap.put("className", className);
                errMap.put("methodName", methodName);
                // TODO 需要处理异常
                throw new RuntimeException("");
            }
        }
        return keyValue;
    }

    /**
     * obj to string
     *
     * @param obj obj
     * @return str
     */
    public static String getStringValue(Object obj) {
        String value = "";
        if (!isNull(obj)) {
            if (obj instanceof Calendar) {
                value = com.css.util.DateUtils.toDateStr((Calendar) obj);
            } else if (obj instanceof Date) {
                value = com.css.util.DateUtils.dateToString((Date) obj);
//            } else if (obj instanceof Timestamp) {
//                value = SwordDateUtils.toDateStr(SwordDateUtils.convSqlTimestampToUtilCalendar((Timestamp) obj));
            } else {
                value = obj.toString();
            }
        }
        return value;
    }

    /**
     * 根据key生成poList的索引
     * 相当于list.stream().collect(Collectors.groupingBy(vo -> getValueByKey(vo, key)));
     *
     * @param list PO列表
     * @param key  要生成索引的主键
     * @param <T>  <T>
     * @return 索引信息
     */
    public static <T> Map<String, T> getIndexByKey(Collection<T> list, String key) {
        final Map<String, T> indexMap = new HashMap<>();
        if (!isNull(list)) {
            for (T vo : list) {
                final String keyValue = getValueByKey(vo, key);
                indexMap.put(keyValue, vo);
            }
        }
        return indexMap;
    }

    public static <T, R> Map<R, T> getIndexByKey(Collection<T> list, Function<T, R> key) {
        final Map<R, T> indexMap = new HashMap<>();
        if (!isNull(list)) {
            for (T vo : list) {
                final R keyValue = key.apply(vo);
                indexMap.put(keyValue, vo);
            }
        }
        return indexMap;
    }

    public static String getUuid() {
        return IdUtil.fastSimpleUUID();
    }

    /**
     * @param key   键值
     * @param value 值
     * @param list  待查列表
     * @return 是否找到
     * @name 在list中查找指定项，看对应key的value是否和传入的一致
     * @description 相关说明
     * @time 创建时间:2022-10-22下午11:17:04
     * @author 黄艳梅
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static boolean findKeyInMapList(String key, String value, List<Map<String, Object>> list) {
        boolean find = false;
        if (list != null && list.size() > 0) {
            for (Map<String, Object> map : list) {
                if (map != null && !map.isEmpty()) {
                    final String str = (String) map.get(key);
                    if (value.equals(str)) {
                        find = true;
                        break;
                    }
                }
            }
        }
        return find;
    }

    /**
     * @param key    键，如:zspmDm
     * @param value  值，如101060200
     * @param skssqq 税款所属期起，可空
     * @param skssqz 税款所属期止，可空
     * @param list   缓存数据列表
     * @return 找到的数据map
     * @name 在list查找单笔有效，且期内有效的记录
     * @description 如：查找品目、子目参数表
     * @time 创建时间:2022-111-10上午11:40:20
     * @author 黄许明
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static Map<String, Object> findSingleInMapListByYxq(String key, String value, Date skssqq, Date skssqz, List<Map<String, Object>> list) {
        Map<String, Object> resMap = new HashMap<String, Object>();
        if (list != null && list.size() > 0) {
            for (Map<String, Object> map : list) {
                if (map != null && !map.isEmpty()) {
                    final String str = (String) map.get(key);
                    boolean yxq = false;//默认期内有效
                    final Date yxqq = cast2Date(map.get("yxqq"));
                    final Date yxqz = cast2Date(map.get("yxqz"));
                    //如果不传属期 或者 配置表中无有效期，则认为不按有效期适配
                    if (skssqq == null || skssqz == null || yxqq == null || yxqz == null) {
                        yxq = true;
                    }
                    //否则，判断属期 和有效期是否有交叉，有则视为期内有效
                    else if (sqAcross(yxqq, yxqz, skssqq, skssqz)) {
                        yxq = true;
                    }
                    //代码吻合且 期内有效，视为找到
                    if (value.equals(str) && yxq) {
                        resMap = map;
                        break;
                    }
                }
            }
        }
        return resMap;
    }

    /**
     *@name 判断两段日期起止 是否有交叉
     *@description 相关说明
     *@time 创建时间：2022-10-22上午02:11:36
     *@param qqA 期起A
     *@param qzA 期止A
     *@param qqB 期起B
     *@param qzB 期止B
     *@return 判断结果
     *@author 历次修订内容、修订人、修订时间等）
     */
    public static boolean sqAcross(Date qqA, Date qzA, Date qqB, Date qzB) {
        boolean rs = false;
        //不为空
        if (qqA == null || qzA == null || qqB == null || qzB == null) {
            return false;
        }
        //期止大于等于对方期起，即为交叉
        if (qzB.compareTo(qqA) >= 0 && qzA.compareTo(qqB) >= 0) {
            rs = true;
        }
        return rs;
    }

    /**
     *@name 将List中大写的key转成标准的小写驼峰式key
     *@description 相关说明
     *@time 创建时间2022-10-22上午09:30:55
     *@param inlist 输入list
     *@return List<Map < String, Object>>
     *@author 黄艳梅
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static List<Map<String, Object>> cast2DefKeyList(List<Map<String, Object>> inlist) {
        final List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        if (inlist == null || inlist.size() == 0) {
            return inlist;
        }
        for (Map<String, Object> map : inlist) {
            final Map<String, Object> newmap = cast2DefKeyMap(map);
            list.add(newmap);
        }
        return list;
    }

    /**
     *@name 把Map中大写的key转成标准的小写驼峰式key
     *@description 相关说明
     *@time 创建时间:2022/10/20 11:10
     *@param req 输入Map
     *@return Map<String, Object>
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> cast2DefKeyMap(Map<String, Object> req) {
        final Map<String, Object> res = new HashMap<String, Object>();
        if (req == null) {
            return res;
        }
        final Iterator it = req.keySet().iterator();
        while (it.hasNext()) {
            final String oldKey = (String) it.next();
            res.put(cast2DefKey(oldKey), req.get(oldKey));
        }
        return res;
    }

    /**
     *@name 把大写的key字符转成标准的小写驼峰式key字符
     *@description 相关说明
     *@time 创建时间:2022/10/20 11:10
     *@param oldkey 原key
     *@return newKey
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static String cast2DefKey(String oldkey) {
        String newKey = oldkey;
        newKey = newKey.toLowerCase();
        while (newKey.indexOf("_") >= 0) {
            final int i = newKey.indexOf("_");
            String befStr = "";
            String aftStr = "";
            if (i > 0) {
                befStr = newKey.substring(0, i);
            }
            if (i < newKey.length() - 1) {
                aftStr = newKey.substring(i + 1, i + 2).toUpperCase().concat(newKey.substring(i + 2));
            }
            newKey = befStr.concat(aftStr);
        }
        return newKey;
    }

    /**
     *@name 转型成String
     *@description 缺省未列举的对象类型会 默认toString()，不排除特定类型转型出来的未知串， 请注意，慎用
     *@time 创建时间:2022/10/20 11:10
     *@param obj 对象
     *@return String
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static String cast2Str(Object obj) {
        String returnVal = null;
        if (obj != null) {
            if (obj instanceof String) {
                returnVal = (String) obj;
            } else if (obj instanceof BigDecimal || obj instanceof Integer || obj instanceof Long) {
                returnVal = obj.toString();
            }
            //先转成BigDecimal，再转成String，可以避免 转型出现 3.0E-4 这样的科学计数法字符串
            else if (obj instanceof Double) {
                final BigDecimal dec = new BigDecimal(obj.toString());
                returnVal = dec.toPlainString();//把科学计数法格式成正常格式
            } else if (obj instanceof Date) {
                final Date da = (Date) obj;
                returnVal = com.css.util.DateUtils.dateToString(da);
            } else if (obj instanceof Calendar) {
                final Calendar ca = (Calendar) obj;
                returnVal = com.css.util.DateUtils.dateToString(ca.getTime());
            } else if (obj instanceof Boolean) {
                final Boolean objBooleanValue = ((Boolean) obj).booleanValue();
                if (objBooleanValue) {
                    returnVal = "Y";
                } else if (!objBooleanValue) {
                    returnVal = "N";
                }
            }
            //默认toString，需注意某些特定类型的转型
            else {
                returnVal = obj.toString();
            }
        }
        return returnVal;
    }

    /**
     *@name 中文名称
     *@description 相关说明
     *@time 创建时间:2022-10-22上午09:54:44
     *@param qqA 期起A
     *@param qzA 期止A
     *@param qqB 期起B
     *@param qzB 期止B
     *@return 判断结果
     *@author jiyunmei
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static boolean compareYxqx(Date qqA, Date qzA, Date qqB, Date qzB) {
        boolean rs = false;
        //不为空
        if (qqA == null || qzA == null || qqB == null || qzB == null) {
            return false;
        }
        //包含
        if (qqA.compareTo(qqB) >= 0 && qzB.compareTo(qzA) >= 0) {
            rs = true;
        }
        return rs;
    }

    /**
     *@name 转型成日期
     *@description 缺省未列举的对象类型会为null，请注意
     *@time 创建时间:2022/10/20 11:10
     *@param obj 对象
     *@return Date
     *@history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static Date cast2Date(Object obj) {
        Date returnVal = null;
        if (obj != null) {
            if (obj instanceof String) {
                if (((String) obj).trim().length() == 0) {
                    returnVal = null;
                } else {
                    returnVal = com.css.util.DateUtils.strToDate((String) obj);
                }
            } else if (obj instanceof Calendar) {
                final Calendar ca = (Calendar) obj;
                returnVal = ca.getTime();
            } else if (obj instanceof Date) {
                returnVal = (Date) obj;
            }
        }
        return returnVal;
    }

    /**
     * @param key   键值
     * @param value 值
     * @param list  待查列表
     * @return 结果列表
     * @name 根据指定项在list中查找数据
     * @description 模糊匹配场景，即trim() like %
     * @time 创建时间:2014-8-14下午08:49:26
     * @author 黄艳梅
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static List<Map<String, Object>> findListByLikeInMapList(String key, String value, List<Map<String, Object>> list) {
        final List<Map<String, Object>> reslist = new ArrayList<Map<String, Object>>();
        if (!GyUtils.isNull(list) && !GyUtils.isNull(value)) {
            for (Map<String, Object> map : list) {
                if (map != null && !map.isEmpty()) {
                    final String str = (String) map.get(key);
                    //模糊匹配
                    if (!GyUtils.isNull(str) && value.startsWith(str.trim())) {
                        reslist.add(map);
                    }
                }
            }
        }
        return reslist;
    }

    public static int[] getYearMonthDayHH24MiMM(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getYearMonthDayHH24MiMM(calendar);
    }

    public static int[] getYearMonthDayHH24MiMM(Calendar calendar) {
        return new int[]{calendar.get(1), calendar.get(2) + 1, calendar.get(5), calendar.get(11), calendar.get(12), calendar.get(13), calendar.get(14)};
    }

    public static String defaultValue(String str1, String str2) {
        if (GyUtils.isNull(str1)) {
            return str2;
        }
        return str1;

    }

    /**
     * 根据key对PoList进行归集
     */
    public static <T> Map<String, List<T>> getCollectionIndexByKey(Collection<T> list, String key) {
        final Map<String, List<T>> indexMap = new HashMap<>();
        if (!isNull(list)) {
            for (T vo : list) {
                final String keyValue = getValueByKey(vo, key);
                if (indexMap.containsKey(keyValue)) {
                    final List<T> tmplist = indexMap.get(keyValue);
                    tmplist.add(vo);
                } else {
                    final List<T> tmplist = new LinkedList<T>();
                    tmplist.add(vo);
                    indexMap.put(keyValue, tmplist);
                }
            }
        }
        return indexMap;
    }


    /**
     * @param list        列表
     * @param key         key字段名
     * @param pKey        上级key字段名
     * @param childrenKey 子节点字段名
     * @return 树形结构数据
     * @name list转成tree
     * 数据要求是tree结构
     * @time 创建时间:2018年5月17日下午3:56:17
     * @author 商健
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    @SuppressWarnings("unchecked")
    public static Collection<Map<String, Object>> list2Tree(Collection<Map<String, Object>> list, String key, String pKey, String childrenKey) {
        if (isNull(list)) {
            return list;
        }
        final Collection<Map<String, Object>> rootList = new ArrayList<>(list.size());
        //TODO 可以改成直接生成集合 by 商健
        final Map<String, Map<String, Object>> indexMap = getIndexByKey(list, key);
        for (Map<String, Object> map : list) {
            final Object pcode = map.get(pKey);
            if (isNull(pcode) || !indexMap.containsKey(pcode)) {
                rootList.add(map);
            } else {
                final Map<String, Object> pNode = indexMap.get(pcode);
                List<Map<String, Object>> childrenNodes = (List<Map<String, Object>>) pNode.get(childrenKey);
                if (isNull(childrenNodes)) {
                    childrenNodes = new LinkedList<>();
                    pNode.put(childrenKey, childrenNodes);
                }
                childrenNodes.add(map);
            }
        }
        return rootList;
    }


    public static boolean isPrimitiveObj(Object obj) {
        if (GyUtils.isNull(obj)) {
            return true;
        }
        final Class<?> clazz = obj.getClass();
        return clazz.isPrimitive() || clazz == Byte.class
                || clazz == Short.class
                || clazz == Integer.class
                || clazz == Long.class
                || clazz == Float.class
                || clazz == Double.class
                || clazz == Character.class
                || clazz == Boolean.class
                || clazz == String.class;
    }


    public static String getValueByRegex(String content, String regex) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(content);
        String value = null;
        while (matcher.find()) {
            value = matcher.group();
        }
        return value;
    }


    /**
     * 将字符串转int
     * @param number
     * @return
     */
    public static int str2int(String number){
        int res=0;
        if(GyUtils.isNull(number)){
            return 0;
        }
        try {
            res=Integer.valueOf(number);
        }catch (Exception e){
            res=0;
        }
        return res;
    }

    /**
     * 将数据库的Object 强转为String
     *
     * @param object
     * @return
     */
    public static String object2Str(Object object) {
        String res = "";
        if (object != null) {
            if (object instanceof Double) {
                res = double2str((double) object);
            } else if (object instanceof Integer) {
                res = String.valueOf(object);
            } else if (object instanceof Timestamp) {
                Timestamp time = (Timestamp) object;
                res = dateToString(time, 0);
            } else if (object instanceof String || object instanceof Float || object instanceof BigDecimal) {
                res = String.valueOf(object);
            } else {
                res = String.valueOf(object);
            }
        }
        return res;
    }

    public static String double2str(double number) {
        DecimalFormat df = new DecimalFormat("#0.00");
        return df.format(number);
    }
    public static String dateToString(Date date, int format) {
        String dates = dateFormatinfo[format];
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dates);
        return simpleDateFormat.format(date);
    }
}